#include <iostream>
#include <sstream>

#include <gtest/gtest.h>

#include "melon/client/thrift_client_pool.h"
#include "obbt/adapters/obbt_state_adapter.h"

using melon::client::ClientPool;

using namespace obbt;

TEST(ObbtStateService, CustomerAccess) {
  for (int i = 0; i < 1; ++i) {
    int64_t customer_id = time(NULL);

    int ret = ObbtStateAdapter::Instance().SetCustomerAccessServerId(customer_id, 3, 2);
    std::cout << "CustomerConnected " << customer_id << " ret=" << ret << std::endl;

    CustomerStatus status;
    ret = ObbtStateAdapter::Instance().GetCustomerStatus(customer_id, &status, 2);
    std::cout << "GetCustomerStatus " << customer_id << " ret=" << ret << std::endl;
    EXPECT_TRUE(status.access_server_id == 3);
  }
}

TEST(ObbtStateService, CustomerStatus) {
  for (int i = 0; i < 1; ++i) {
    int64_t customer = 333000 + time(NULL);
    int64_t engineer = 1000 + time(NULL);

    int ret = ObbtStateAdapter::Instance().SetCustomerAccessServerId(customer, 3, 2);
    ret = ObbtStateAdapter::Instance().SetCustomerServingEngineer(customer, "18611951882", engineer, 0, 1000001, 0, AllocType::BASIC, 2);
    ret = ObbtStateAdapter::Instance().SetCustomerMobile(customer, "18611951882", 2);

    CustomerStatus status;
    ret = ObbtStateAdapter::Instance().GetCustomerStatus(customer, &status, 2);
    std::cout << "GetCustomerStatus " << customer << " ret=" << ret << std::endl;
    EXPECT_TRUE(status.access_server_id == 3);
    EXPECT_TRUE(status.serving_engineer == engineer);
    EXPECT_TRUE(status.assignment_id == 1000001);
    EXPECT_TRUE(status.mobile == "18611951882");
  }
}

TEST(ObbtStateService, EngineerAccess) {
  for (int i = 0; i < 1; ++i) {
    int64_t engineer = 1000 + time(NULL);

    int ret = ObbtStateAdapter::Instance().SetEngineerAccessServerId(engineer, 3, 2);
    std::cout << "SetEngineerAccessServerId " << engineer << " ret=" << ret << std::endl;

    EngineerStatus status;
    ret = ObbtStateAdapter::Instance().GetEngineerStatus(engineer, &status, 2);
    std::cout << "GetEngineerStatus " << engineer << " ret=" << ret << std::endl;
    EXPECT_TRUE(ret == 0);
    EXPECT_EQ(status.access_server_id, 3);
  }
}

TEST(T, EngineerStatus) {
  int64_t engineer = 1000 + time(NULL);
  int ret = ObbtStateAdapter::Instance().SetEngineerAccessServerId(engineer, 3, 2);

  for (int i = 0; i < 3; ++i) {
    int64_t customer = 333000 + i;
    ret = ObbtStateAdapter::Instance().AddEngineerServingCustomer(engineer, customer, "18611951882", 2);
  }

  for (int i = 3; i < 6; ++i) {
    int64_t customer = 333000 + i;
    ret = ObbtStateAdapter::Instance().AddEngineerAllocatedCustomer(engineer, customer, 2);
  }

  EngineerStatus status;
  ret = ObbtStateAdapter::Instance().GetEngineerStatus(engineer, &status, 2);
  EXPECT_EQ(ret, 0);
  std::cout << "GetEngineerStatus " << engineer << " ret=" << ret << std::endl;
  EXPECT_EQ(status.access_server_id, 3);
  EXPECT_EQ(status.serving_customers.size(), 3);
  EXPECT_TRUE(status.serving_customers[0] == 333000);
  EXPECT_TRUE(status.serving_customers[1] == 333001);
  EXPECT_TRUE(status.serving_customers[2] == 333002);

  EXPECT_EQ(status.allocated_customers.size(), 3);
  EXPECT_TRUE(status.allocated_customers[0] == 333003);
  EXPECT_TRUE(status.allocated_customers[1] == 333004);
  EXPECT_TRUE(status.allocated_customers[2] == 333005);

  ret = ObbtStateAdapter::Instance().AddEngineerServingCustomer(engineer, 333003, "18611951882", 2);

  EngineerStatus status2;
  ret = ObbtStateAdapter::Instance().GetEngineerStatus(engineer, &status2, 2);
  EXPECT_EQ(status2.serving_customers.size(), 4);
  EXPECT_TRUE(status2.serving_customers[0] == 333000);
  EXPECT_TRUE(status2.serving_customers[1] == 333001);
  EXPECT_TRUE(status2.serving_customers[2] == 333002);
  EXPECT_TRUE(status2.serving_customers[3] == 333003);

  EXPECT_EQ(status2.allocated_customers.size(), 2);
  EXPECT_TRUE(status2.allocated_customers[0] == 333004);
  EXPECT_TRUE(status2.allocated_customers[1] == 333005);

  ret = ObbtStateAdapter::Instance().RemoveEngineerServingCustomer(engineer, 333001, 2);
  ret = ObbtStateAdapter::Instance().RemoveEngineerServingCustomer(engineer, 333003, 2);
  ret = ObbtStateAdapter::Instance().RemoveEngineerAllocatedCustomer(engineer, 333004, 2);
  EngineerStatus status3;
  ret = ObbtStateAdapter::Instance().GetEngineerStatus(engineer, &status3, 2);
  EXPECT_EQ(status3.serving_customers.size(), 2);
  for(size_t i = 0; i < status3.serving_customers.size(); ++i) {
    std::cout << status3.serving_customers[i] << std::endl;
  }
  EXPECT_EQ(status3.serving_customers[0], 333000);
  EXPECT_EQ(status3.serving_customers[1], 333002);
  EXPECT_EQ(status3.allocated_customers.size(), 1);
  EXPECT_EQ(status3.allocated_customers[0], 333005);
}

TEST(T, T) {
  EngineerStatus status4;
  int ret = ObbtStateAdapter::Instance().GetEngineerStatus(10004, &status4, 2);
  std::cout << "skills.size=" << status4.profile.skills.size() << std::endl;
  std::cout << "name=" << status4.profile.name << std::endl;
  std::cout << "slogan=" << status4.profile.slogan << std::endl;
  std::cout << "dominant=" << status4.profile.dominant << std::endl;
}

TEST(ObbtStateService, EngineerList) {
  time_t t = time(NULL);
  int16_t problem_type = t & 0x7FFF;
  for (int i = 0; i < 10; ++i) {
    int64_t engineer = 1000 + t + i;

    int ret = ObbtStateAdapter::Instance().InsertEngineerList(problem_type, engineer, 0, 2);
    std::cout << "InsertEngineerList " << engineer << " ret=" << ret << std::endl;
  }

  std::map<int32_t, int64_t> engineers;
  int ret = ObbtStateAdapter::Instance().GetEngineerList(problem_type, 0, 5, &engineers, 2);
  std::cout << "GetEngineerList " << problem_type << " ret=" << ret << " size=" << engineers.size() << std::endl;
  EXPECT_TRUE(engineers.size() == 5);
}

struct Args {
  Args(int c, char ** v) : argc(c), argv(v) {}
  int argc;
  char** argv;
};
void * ThreadFun(void * p) {
  Args * args = (Args*)p;
  testing::InitGoogleTest(&args->argc, args->argv);
  return (void*)RUN_ALL_TESTS();
}

const int kThreadCount = 1;

int main(int argc, char** argv) {
  LOG_INIT("./test.log", "DEBUG");
  pthread_t ts[kThreadCount];

  Args args(argc, argv);
  for (int i = 0; i < kThreadCount; ++i) {
    pthread_create(&ts[i], NULL, ThreadFun, &args);
  }

  for (int i = 0; i < kThreadCount; ++i) {
    pthread_join(ts[i], NULL);
  }
  return 0;
} 

